package com.xiexie.seckill.config;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.xiexie.seckill.pojo.User;
import com.xiexie.seckill.service.IUserService;
import com.xiexie.seckill.utils.CookieUtil;
import com.xiexie.seckill.vo.RespBean;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.concurrent.TimeUnit;

/**
 * 限流注解拦截器
 */
@Component
public class AccessLimitInterceptor implements HandlerInterceptor {

    @Autowired
    private IUserService userService;

    @Autowired
    private RedisTemplate redisTemplate;

    @Override
    public boolean preHandle(
            HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

        // 获取当前用户
        User currentUser = getCurrentUser(request, response);

        if (handler instanceof HandlerMethod) {
            HandlerMethod hm = (HandlerMethod) handler;
            AccessLimit accessLimit = hm.getMethodAnnotation(AccessLimit.class);
            if (null == accessLimit) {
                return true;
            }
            int second = accessLimit.second();
            int maxCount = accessLimit.maxCount();
            boolean needLogin = accessLimit.needLogin();

            if (needLogin) {
                if (null == currentUser) {
                    render(response, "不存在当前用户");
                    return false;
                }
            }

            ValueOperations valueOperations = redisTemplate.opsForValue();
            String uri = request.getRequestURI();
            String key = uri + ":" + currentUser.getId();
            Integer count = (Integer) valueOperations.get(key);
            if (count == null) {
                valueOperations.set(key, 1, 5, TimeUnit.SECONDS);
            } else if (count < 5) {
                valueOperations.increment(key);
            } else {
                render(response, "访问过于频繁，请稍后访问");
                return false;
            }
        }
        return false;
    }

    /**
     * 构建返回对象
     * @param response
     * @param errorMsg
     */
    private void render(HttpServletResponse response, String errorMsg) throws IOException {
        response.setContentType("application/json");
        response.setCharacterEncoding("UTF-8");
        PrintWriter writer = response.getWriter();
        RespBean respBean = RespBean.error(errorMsg);
        writer.write(new ObjectMapper().writeValueAsString(respBean));
        writer.flush();
        writer.close();
    }

    /**
     * 获取当前用户
     *
     * @param request
     * @param response
     * @return
     */
    private User getCurrentUser(HttpServletRequest request, HttpServletResponse response) {

        String ticket = CookieUtil.getCookieValue(request, "userTicket");
        if (StringUtils.isEmpty(ticket)) {
            return null;
        }
        return userService.getUserByCookie(ticket, request, response);
    }
}
